我們用 SMART——Specific(具體)、Measurable(可衡量)、Achievable(可達成)、Relevant(具關聯)、Time-bound(有時限)——把每個故事拆成五天,作為每次動手造輪子前的五個檢查問題。
本篇是故事五「擔心客戶看不懂 OpenAPI 文件,我急到沒看到 Postman,先刻了一個範例 App」的 Measurable 篇:什麼證據可以證明問題已經解決?
本篇定位:定義 API 導入成功的證據,避免範例 App 的畫面成為錯誤的驗收焦點。
範例 App 示範完之後,我們自己的檢討會氣氛不錯。畫面該有的都有:登入頁、表單、送出按鈕、回應區塊、紅色的錯誤提示,還有人提議加個載入動畫。整場會議討論的都是這個 App,沒有人問過更基本的問題:客戶自己的工程師,回到他自己的專案裡,能不能在沒有我們的情況下,發出第一個正確的請求?
這個問題後來被問出來,是因為客戶又寄了一封信,說某個欄位傳上去沒有作用。對照 Swagger UI 才發現,文件上標的欄位名稱和服務端實際接受的不一樣——服務端幾個月前改過名,文件沒跟著更新。客戶照文件送了舊的欄位名,服務端不認得,於是靜靜地忽略它:不報錯,也不生效。
這種 API 文件(或規格)與實際實作不同步的狀況,社群裡有人稱為 API drift 或 spec drift,但那不是任何標準組織定義的術語。而我們的範例 App 為什麼一直沒撞到?因為它是照著實際服務寫的,不是照著文件寫的。它繞過了那個錯誤,也讓我們對錯誤失明了兩週——我們花力氣做出來的「證明客戶會用了」的東西,同時遮住了客戶真正會撞到的那道牆。
問題出在我們挑了一個好看但無關的成功指標。App 能跑,證明的是我們的前端能呼叫我們的後端;客戶要的是他的程式能呼叫我們的後端。兩者走的路完全不同:我們知道存取權杖從哪裡來、哪個欄位不用填、測試環境的網址是什麼。這些知識全部留在我們腦裡,一行也沒進入交付物——App 跑起來的那一刻,我們驗收的是自己的隱性知識,不是客戶的可操作性。這比沒驗收更危險,因為它會產生「已經完成」的感覺,讓所有人停止追問。
Measurable 在這裡的意義,是把驗收對象移到那個不認識我們的人身上:如果客戶的工程師今天全部換一批,只拿到我們的交付物,他能不能自己走完一次?
還有一個容易被忽略的維度是環境。測試與正式的網址、憑證、資料範圍通常不同,客戶第一次踩雷往往就在這裡:用測試的權杖打正式端點,或把測試資料寫進正式庫。畫面再像產品也不會自動處理它。
把導入的完成條件寫成一條可重現的成功路徑,而不是一份畫面檢查表。以下每一項都由客戶端的人執行,我們在旁邊看。
這張表完全不提畫面,通過與否只跟「請求發得出去、回應讀得懂、環境換得掉」有關。
要讓最後一項成立,得把檢查本身自動化。OpenAPI 既然是契約,就讓它能被檢查——檢查分三層,很多團隊做完前兩層就以為做完了。第一層是規格語法驗證:確認檔案本身合法、工具讀得進去;OpenAPI Initiative 提供的 JSON Schema 可以拿來驗,但僅供參考,規格正文才具權威。第二層是風格與治理檢查:命名是否一致、端點與參數有沒有描述與範例值,這一層可以掛進 CI 管線強制執行。第三層才是契約測試:照著規格產生請求打到實際服務,再拿回應比對規格宣告的結構、狀態碼與標頭。
前兩層只證明文件寫得整齊,唯有第三層會抓出文件與實作不同步。那個被忽略的欄位就是例子:語法沒問題、風格也沒問題,只有在有人真的照文件送一次並檢查結果時才會現形。它能存活幾個月,不是因為難發現,是因為沒有一個流程會踩到它。文件不會自己保持正確,只有被執行過的文件才會。
最後是證據的性質:留下來的東西要離開我們也能用,而且可以重複執行。前者是客戶自己拿著就能跑,不必我們幫忙部署、填設定、出事再回頭找原作者;後者是同一份東西下一版還能再跑,並說得出它是通過還是壞了。拿這兩條去照那個 App,它一條都不符合。
API 教學的完成條件不是我們多做了一個畫面,而是使用者不需要找原作者,也能完成正確請求。把驗收標準從「我們展示了什麼」換成「他獨立做到了什麼」,很多看起來很有誠意的工作會立刻現出原形,包括我們那兩週。
驗收方式也會反過來決定交付物的形狀。成功指標是「客戶能自己發請求」,我們自然會去補文件、補範例、補環境設定;成功指標是「App 跑得起來」,我們就只會一直改前端。指標選錯,努力的方向從第一天就偏了,而且偏得毫無痛感。
那麼,要讓客戶能自己發請求,最省力的路徑是什麼?其實整條路上早就鋪著現成工具,只是那兩週我一次也沒抬頭看。明天來盤點。